﻿using Biotech.Log;
using project.B12.IService;
using project.B12.Model.Error;
using project.B12.Model.Models;
using software.Common.MVVM;
using System.Collections.ObjectModel;
using System.Data;
using System.Data.SQLite;
using System.Diagnostics;

namespace project.B12.Service
{
    public class LogService : ObservableObject, ILogService
    {

        private List<TableLog> paginationCollection = new List<TableLog>();

        public List<TableLog> PaginationCollection
        {
            get => paginationCollection;
            set { paginationCollection = value; RaisePropertyChanged(); }
        }

        public ObservableCollection<ErrCodeModel> WarnLogs { get; }

        public List<TableLog> AllLogData { get; set; } = new List<TableLog>();
        private int count;

        public int Count
        {
            get => count;
            set { count = value; RaisePropertyChanged(); CurrentPageChanged(); }
        }

        private int countPerPage = 20;

        public int CountPerPage
        {
            get => countPerPage;
            set { countPerPage = value; RaisePropertyChanged(); CurrentPageChanged(); }
        }

        private int currentPage;

        public int CurrentPage
        {
            get => currentPage;
            set { currentPage = value; RaisePropertyChanged(); CurrentPageChanged(); }
        }

        private void CurrentPageChanged()
        {
            PaginationCollection = AllLogData.Skip((CurrentPage - 1) * countPerPage).Take(countPerPage).ToList();
        }

        private readonly IPublicResource _publicResource;

        public LogService(IPublicResource publicResource)
        {
            _publicResource = publicResource;
            var ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString();
            var vers = ver?.Split('.');
            // 版本号 软件名
            LoggerFactory.Instance.Version = vers?[0] + '.' + vers?[1];
            LoggerFactory.Instance.SoftwareName = "B12";

            sqliteLogger = new SqliteLogger(LoggerFactory.Instance.SoftwareName, LoggerFactory.Instance.Version);

            // 记录的日志类型
            //LoggerFactory.Instance.AddLoggerType(LoggerType.File);
            LoggerFactory.Instance.AddLoggerType(LoggerType.SQLite);
            LoggerFactory.Instance.UserName=_publicResource.UserName;
            LoggerFactory.Instance.CurrentLogger.LogInfo(/*DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss ") +*/ "启动应用软件");
            //LoggerFactory.Instance.CurrentLogger.LogDebug("Debug", "1", "2");
            //LoggerFactory.Instance.CurrentLogger.LogInfo("Hello,this is a info log");
            //LoggerFactory.Instance.CurrentLogger.LogWarning("Hello,this is a warning log");
            //LoggerFactory.Instance.CurrentLogger.LogError("Hello,this is a error log");
            //LoggerFactory.Instance.CurrentLogger.LogFatal("Hello,this is a fatal log");
            //LoggerFactory.Instance.CurrentLogger.LogFatal("Hello,this is a fatal log");
            //LoggerFactory.Instance.CurrentLogger.LogDebug("Hello,this is a fatal log");

            WarnLogs = new ObservableCollection<ErrCodeModel>(RecentlyWarnShow());
        }

        private readonly SqliteLogger sqliteLogger;
        private readonly SQLiteConnectionStringBuilder connstr = new SQLiteConnectionStringBuilder();
        private readonly SQLiteConnection conn = new SQLiteConnection();

        /// <summary>
        /// 刷新
        /// </summary>
        /// <returns></returns>
        private List<TableLog> RecentlyShow()
        {
            try
            {
                if (File.Exists(sqliteLogger._FilePath))
                {
                    connstr.DataSource = sqliteLogger._FilePath;
                    conn.ConnectionString = connstr.ToString();
                    conn.Open();

                    var dt = new DataTable();

                    using (var command = new SQLiteCommand(conn))
                    {
                        //command.CommandText = "select Type, User, DateTime, Text, InstrumentID, ModuleName From TableLog,AlertLog order by rowid desc";
                        command.CommandText = "select Type, User, DateTime, Text, InstrumentID, ModuleName as category from TableLog " +
                                              "union all " +
                                              "select Type, User, DateTime, Text, InstrumentID, ModuleName as category from AlertLog " +
                                              "union all " +
                                              "select Type, User, DateTime, Text, InstrumentID, ModuleName as category from SystemLog " +
                                              "order by DateTime desc";
                        var adapter = new SQLiteDataAdapter(command);
                        adapter.Fill(dt);
                    }

                    conn.Close();

                    var toList = new CovertListHelper();
                    var list = toList.ConvertToList<TableLog>(dt) ?? new List<TableLog>();
                    return list;

                    // 排序list

                    //return dt;
                }
                else
                {
                    return new List<TableLog>();
                }
            }
            catch (Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(),"","软件");
            }
           return new List<TableLog>();
        }

        private List<ErrCodeModel> RecentlyWarnShow()
        {
            try
            {
                if (File.Exists(sqliteLogger._FilePath))
                {
                    connstr.DataSource = sqliteLogger._FilePath;
                    conn.ConnectionString = connstr.ToString();
                    conn.Open();
                    var dt = new DataTable();

                    using (var command = new SQLiteCommand(conn))
                    {
                        command.CommandText = "select Type, User, DateTime, Text, InstrumentID, ModuleName From AlertLog order by rowid desc";
                        var adapter = new SQLiteDataAdapter(command);
                        adapter.Fill(dt);
                    }

                    conn.Close();

                    var toList = new CovertListHelper();
                    var list = toList.ConvertToList<TableLog>(dt);
                    var warnLogs = new List<ErrCodeModel>();
                    if (list == null) return warnLogs;
                    foreach (var item in list)
                    {
                        var codeItem =
                            SoftwareException.GetString(item.Text);

                        if (codeItem != null)
                        {
                            warnLogs.Add(new ErrCodeModel()
                            {
                                ErrCode = codeItem.ErrCode,
                                Message = codeItem.Message,
                                DateTime = item.DateTime,
                                Module = codeItem.Module,
                                Name = codeItem.Name,
                                Reason = codeItem.Reason,
                                Solution = codeItem.Solution,
                                Type = (LogType)Enum.Parse(typeof(LogType), item.Type)
                            });
                        }
                    }
                    return warnLogs;

                    //return dt;
                }
                else
                {
                    return new List<ErrCodeModel>();
                }
            }
            catch (Exception ex)
            {
                LoggerFactory.Instance.CurrentLogger.LogInfo(ex.ToString(), "", "软件");
            }
            return new List<ErrCodeModel>();
        }

        public ErrCodeModel QueryLast()
        {
            if (File.Exists(sqliteLogger._FilePath))
            {
                connstr.DataSource = sqliteLogger._FilePath;
                conn.ConnectionString = connstr.ToString();
                conn.Open();

                var dt = new DataTable();

                using (var command = new SQLiteCommand(conn))
                {
                    command.CommandText = "select * FROM AlertLog order by rowid desc LIMIT 1";
                    var adapter = new SQLiteDataAdapter(command);
                    adapter.Fill(dt);
                }

                conn.Close();

                var toList = new CovertListHelper();
                var list = toList.ConvertToList<TableLog>(dt);
                var warnLog = new ErrCodeModel();
                if (list == null) return warnLog;
                foreach (var item in list)
                {
                    var codeItem =
                        SoftwareException.GetString(item.Text);

                    if (codeItem != null)
                    {
                        warnLog = new ErrCodeModel()
                        {
                            ErrCode = codeItem.ErrCode,
                            Message = codeItem.Message,
                            DateTime = item.DateTime,
                            Module = codeItem.Module,
                            Name = codeItem.Name,
                            Reason = codeItem.Reason,
                            Solution = codeItem.Solution,
                            Type = (LogType)Enum.Parse(typeof(LogType), item.Type)
                        };
                    }
                    else
                    {
                        warnLog = new ErrCodeModel()
                        {
                            Message = item.Text,
                        };
                    }
                }
                return warnLog;
            }
            else
            {
                return new ErrCodeModel();
            }

            //return dsTarget.Tables["Log"];
        }

        private List<TableLog> QueryLog(string startMonth, string endMonth, string type, string instrumentId, string moduleName, string startTime, string endTime)
        {
            var dsTarget = new DataSet();

            startTime = startTime.Remove(11);
            startTime += "00:00:00";
            endTime = endTime.Remove(11);
            endTime += "23:59:59";

            var theFolder = new DirectoryInfo(sqliteLogger._DirectoryPath);
            //string filePath = Log.LoggerFactory.SoftwareName + "_" + Log.LoggerFactory.Version + "_" + "*.db";
            var filePath = LoggerFactory.Instance.SoftwareName + "_" + "*.db";
            var fileInfo = theFolder.GetFiles(filePath, SearchOption.AllDirectories);
            //Console.WriteLine(sqliteLogger._FilePath);
            var fileName = new List<string>();
            string name;
            foreach (var t in fileInfo)
            {
                name = t.Name;
                name = name.Substring(name.IndexOf("_", name.IndexOf("_", StringComparison.Ordinal) + 1, StringComparison.Ordinal) + 1, 6); // 获取日期
                if (int.Parse(name) >= int.Parse(startMonth) && int.Parse(name) <= int.Parse(endMonth))
                {
                    fileName.Add(t.Name);
                }
            }
            var tableName = "TableLog";
            if (type == "Warning" || type == "Error" || type == "Fatal" || type == "AlertAll")
            {
                tableName = "AlertLog";
            }
            if (type == "System")
            {
                tableName = "SystemLog";
            }

            var sql =
                $"select Type, User, DateTime, Text, InstrumentID, ModuleName From {tableName} where DateTime Between \'{startTime}.000\' and \'{endTime}.999\' ";

            var strText = $"查询时间{startTime}至{endTime}";

            if (type != "All" && type != "AlertAll" && type != "NormalAll")
            {
                sql += $"and Type = \"{type}\" ";
                strText += $",类型{type}";
            }

            if (instrumentId != "All")
            {
                sql += $"and InstrumentID = \"{instrumentId}\" ";
                strText += $",设备号{instrumentId}";
            }

            if (moduleName != "All")
            {
                sql += $"and ModuleName = \"{moduleName}\" ";
                strText += $",模块名{moduleName}";
            }
            sql += "order by rowid desc";

            // 写日志
            //LoggerFactory.Instance.CurrentLogger.LogSystem(strText, string.Empty);
            Debug.WriteLine(strText);

            for (var i = fileName.Count - 1; i >= 0; i--)
            {
                var dsSource = new DataSet();
                connstr.DataSource = sqliteLogger._DirectoryPath + "\\\\" + fileName[i];
                conn.ConnectionString = connstr.ToString();
                conn.Open();
                using (var adapter = new SQLiteDataAdapter(sql, conn))
                {
                    adapter.Fill(dsSource, "Log");
                }

                dsTarget.Merge(dsSource);   // 将源数据集的DictionaryType表合并到目标数据集中

                conn.Close();
            }

            var toList = new CovertListHelper();

            var list = toList.ConvertToList<TableLog>(dsTarget.Tables["Log"]!) ?? new List<TableLog>();
            return list;

            //return dsTarget.Tables["Log"];
        }

        public void Search(DateTime startData, DateTime endData, string type, string? text)
        {
            try
            {
                var startMonth = startData.ToString("yyyyMM");
                var endMonth = endData.ToString("yyyyMM");
                var str1 = type;
                var str2 = "All";
                var str3 = "All";

                var startTime = startData.ToString("u");
                var endTime = endData.ToString("u");

                var list = str1 == "All" ? RecentlyShow() : QueryLog(startMonth, endMonth, str1, str2, str3, startTime, endTime);

                var start = Convert.ToDateTime(startTime);
                var end = Convert.ToDateTime(endTime);
                AllLogData = list.Where(x => (text == null || x.Text.Contains(text))
                                             && (Convert.ToDateTime(x.DateTime).Day >= start.Day
                                              && Convert.ToDateTime(x.DateTime).Day <= end.Day))
                        .ToList();

                Count = AllLogData.Count;
                CurrentPage = 1;
                //PaginationCollection = allLogData.Take(countPerPage).ToList();
            }
            catch (Exception ex)
            {
                _ = new SoftwareException("日志查询失败", ex);
            }
        }

        public void Show()
        {
            try
            {
                // 获取所有日志（无筛选）
                AllLogData = RecentlyShow();
                Count = AllLogData.Count;
                PaginationCollection = AllLogData.Take(countPerPage).ToList();
                CurrentPage = 1;
            }
            catch (Exception ex)
            {
                _ = new SoftwareException("日志更新失败", ex);
            }
        }

        public void LogDebug(string text)
        {
            LoggerFactory.Instance.CurrentLogger.LogDebug(text);
        }
    }

    public class CovertListHelper
    {
        public List<T>? ConvertToList<T>(DataTable? dt) where T : new()
        {
            var ts = new List<T>();
            if (dt == null)
                return null;
            foreach (DataRow dr in dt.Rows)
            {
                var t = new T();
                var propertys = t.GetType().GetProperties();
                foreach (var pi in propertys)
                {
                    var tempName = pi.Name;
                    if (dt.Columns.Contains(tempName))
                    {
                        if (!pi.CanWrite) continue;
                        {
                            var value = dr[tempName];
                            if (value != DBNull.Value)
                            {
                                if (pi.GetMethod != null && pi.GetMethod.ReturnParameter.ParameterType.Name == "Int32")
                                {
                                    value = Convert.ToInt32(value);
                                }
                                pi.SetValue(t, value, null);
                            }
                        }
                    }
                }
                ts.Add(t);
            }
            return ts;
        }
    }
}
